// Copyright 2022 jeff.li. and/or its affiliates.

#pragma once

#include <type_traits>

#include <tbir/runtime/container.h>
#include <tbir/runtime/object.h>
#include <tbir/runtime/runtime_value.h>

namespace tbir::runtime {
    /******************************************************************************
     * Generic Constructor for python
     *****************************************************************************/
    namespace Kernel_Iterable {
        // iterable object
        TURBO_FORCE_INLINE File make(File obj) {
            return obj;
        }

        // iterator
        TURBO_FORCE_INLINE Iterator make(Iterator obj) {
            return obj;
        }

        // generic iterator
        Iterator make(const Any &obj);

        template<class T, typename = typename std::enable_if<!is_runtime_value<T>::value>::type>
        TURBO_FORCE_INLINE Iterator make(const T &obj) {
            GenericValueConverter<RTView> Converter;
            return make(static_cast<const Any &>(Converter(obj)));
        }
    }  // namespace Kernel_Iterable

    namespace Kernel_bool {
        TURBO_FORCE_INLINE constexpr bool make() noexcept {
            return 0;
        }

        TURBO_FORCE_INLINE constexpr bool make(int32_t i32) noexcept {
            return static_cast<bool>(i32);
        }

        TURBO_FORCE_INLINE constexpr bool make(int64_t i64) noexcept {
            return static_cast<bool>(i64);
        }

        TURBO_FORCE_INLINE constexpr bool make(float d32) noexcept {
            return static_cast<bool>(d32);
        }

        TURBO_FORCE_INLINE constexpr bool make(double d64) noexcept {
            return static_cast<bool>(d64);
        }

        TURBO_FORCE_INLINE constexpr bool make(bool b) noexcept {
            return b;
        }

        template<typename T, typename = typename std::enable_if<!is_runtime_value<T>::value>::type>
        TURBO_FORCE_INLINE bool make(const T &c) {
            return c.size() != 0;
        }

        bool make(const Any &c);
    }  // namespace Kernel_bool

    namespace Kernel_int64_t {
        TURBO_FORCE_INLINE int64_t make() {
            return 0;
        }

        TURBO_FORCE_INLINE int64_t make(int32_t i32) {
            return static_cast<int64_t>(i32);
        }

        TURBO_FORCE_INLINE int64_t make(int64_t i64) {
            return i64;
        }

        TURBO_FORCE_INLINE int64_t make(float d32) {
            return static_cast<int64_t>(d32);
        }

        TURBO_FORCE_INLINE int64_t make(double d64) {
            return static_cast<int64_t>(d64);
        }

        TURBO_FORCE_INLINE int64_t make(bool b) {
            return static_cast<int64_t>(b);
        }

        int64_t make(const String &us, int64_t base = 10);

        int64_t make(const Unicode &us, int64_t base = 10);

        int64_t make(const Any &c, int64_t base = 10);
    }  // namespace Kernel_int64_t

    namespace Kernel_double {
        TURBO_FORCE_INLINE double make(int32_t i32) {
            return static_cast<double>(i32);
        }

        TURBO_FORCE_INLINE double make(int64_t i64) {
            return static_cast<double>(i64);
        }

        TURBO_FORCE_INLINE double make(float d32) {
            return static_cast<double>(d32);
        }

        TURBO_FORCE_INLINE double make(double d64) {
            return d64;
        }

        TURBO_FORCE_INLINE double make(bool b) {
            return static_cast<double>(b);
        }

        double make(const String &us);

        double make(const Unicode &us);

        double make(const Any &c);
    }  // namespace Kernel_double

    namespace Kernel_String {
        TURBO_FORCE_INLINE String make() {
            return String();
        }

        TURBO_FORCE_INLINE String make(String s) {
            return s;
        }

        TURBO_FORCE_INLINE String make(string_view s) {
            return String(s.data(), s.size());
        }

        TURBO_FORCE_INLINE String make(const char *const s) {
            return String(string_view(s));
        }

        String make(const Unicode &us, const Unicode &encoding = U"UTF-8");

        String make(const Any &c);
    }  // namespace Kernel_String

    namespace Kernel_Unicode {
        TURBO_FORCE_INLINE Unicode make() {
            return Unicode();
        }

        TURBO_FORCE_INLINE Unicode make(unicode_view s) {
            return Unicode(s.data(), s.size());
        }

        TURBO_FORCE_INLINE Unicode make(Unicode s) {
            return s;
        }

        TURBO_FORCE_INLINE Unicode make(const char32_t *const s) {
            return Unicode(s);
        }

        Unicode make(int32_t i32);

        TURBO_FORCE_INLINE Unicode make(bool b) {
            static char32_t const repr[2][6] = {U"False", U"True\0"};
            return repr[b];
        }

        Unicode make(int64_t value);

        Unicode make(double d64);

        Unicode make(float d32);

        Unicode make(const Any &c);

        Unicode make(const IUserDataSharedViewRoot &c);
    }  // namespace Kernel_Unicode

    namespace Kernel_Dict {
        TURBO_FORCE_INLINE Dict make() {
            return Dict{};
        }

        TURBO_FORCE_INLINE Dict make(std::initializer_list<Dict::value_type> init_args) {
            return Dict(init_args);
        }

        Dict make(const Dict &c);

        Dict make(const Any &c);
    }  // namespace Kernel_Dict

    namespace Kernel_Tuple {
        TURBO_FORCE_INLINE Tuple make() {
            return Tuple();
        }

        TURBO_FORCE_INLINE Tuple make(std::initializer_list<RTValue> init_args) {
            return Tuple(init_args);
        }
    }  // namespace Kernel_Tuple

    namespace Kernel_List {
        TURBO_FORCE_INLINE List make() {
            return List();
        }

        TURBO_FORCE_INLINE List make(std::initializer_list<RTValue> init_args) {
            return List(init_args);
        }

        TURBO_FORCE_INLINE List make(const List &c) {
            return List(c.begin(), c.end());
        }

        TURBO_FORCE_INLINE List make(const Set &c) {
            return List(c.begin(), c.end());
        }

        List make(const Iterator &c);

        List make(const Any &c);
    }  // namespace Kernel_List

    namespace Kernel_Set {
        TURBO_FORCE_INLINE Set make() {
            return Set();
        }

        TURBO_FORCE_INLINE Set make(std::initializer_list<RTValue> init_args) {
            return Set(init_args);
        }

        TURBO_FORCE_INLINE Set make(const Set &c) {
            return Set(c.begin(), c.end());
        }

        TURBO_FORCE_INLINE Set make(const List &c) {
            return Set(c.begin(), c.end());
        }

        Set make(const Iterator &c);

        Set make(const Any &c);
    }  // namespace Kernel_Set

    namespace Kernel_NDArray {
        NDArray make(const Any &list,
                     const List &shape,
                     const Unicode &dtype_str,
                     const Unicode &ctx_str = U"cpu");

        NDArray make(const List &list,
                     const List &shape,
                     const Unicode &dtype_str,
                     const Unicode &ctx_str = U"cpu");

        NDArray make(const FTList <int64_t> &list,
                     const List &shape,
                     const Unicode &dtype_str,
                     const Unicode &ctx_str = U"cpu");

        NDArray make(const FTList<double> &list,
                     const List &shape,
                     const Unicode &dtype_str,
                     const Unicode &ctx_str = U"cpu");

        NDArray make(int64_t scalar,
                     const List &shape,
                     const Unicode &dtype_str,
                     const Unicode &ctx_str = U"cpu");

        NDArray make(double scalar,
                     const List &shape,
                     const Unicode &dtype_str,
                     const Unicode &ctx_str = U"cpu");
    }  // namespace Kernel_NDArray

    namespace Kernel_Trie {
        TURBO_FORCE_INLINE Trie make() {
            return Trie();
        }

        Trie make(const Dict &d);
    }  // namespace Kernel_Trie

    namespace Kernel_Regex {
        template<typename... ARGS>
        TURBO_FORCE_INLINE Regex make(ARGS &&... args) {
            return Regex(std::forward<ARGS>(args)...);
        }
    }  // namespace Kernel_Regex

    namespace Kernel_OpaqueObject {
        template<typename... ARGS>
        TURBO_FORCE_INLINE OpaqueObject make(ARGS &&... args) {
            return OpaqueObject(std::forward<ARGS>(args)...);
        }
    }  // namespace Kernel_OpaqueObject

}  // namespace tbir::runtime
